import {IAttribute, IFragmentResult, InnerVarying, IUniform, IVarying, Program} from "./Program";
import {Vector3} from "../math/Vector3";
import {Matrix4} from "../math/Matrix4";
import {Vector2} from "../math/Vector2";
import {Texture} from "../asserts/Texture";
import {Ambient} from "../scene/lights/Ambient";
import {PointLight} from "../scene/lights/PointLight";
export interface Varying  extends IVarying {
    vUv: Vector2;
    vWorldPosition: Vector3;
    vNormal: Vector3;
}
export interface Attribute extends IAttribute  {
    aPosition: Vector3;
    aUv: Vector2;
    aNormal: Vector3;
}
export interface Uniform extends IUniform {
    uMVPMatrix: Matrix4;
    uDiffuseTexture: Texture,
    uSpecularTexture: Texture,
    uAmbient?: Ambient;
    uPointLights?: PointLight[];
    uCameraPoint: Vector3;
    uShininess: number;
}
export class BlingPhongProgram extends Program<Attribute, Uniform, Varying> {
    vertexShader(attribute: Attribute, uniform: Uniform): InnerVarying & Varying {
        const {aPosition, aUv, aNormal} = attribute;
        const {uMVPMatrix} = uniform;
        // console.log('aUv: ', aUv.toString());
        // console.log('aPosition: ', aPosition.toString());
        return {
            vPosition: aPosition.appliedMatrix4(uMVPMatrix),
            vUv: aUv,
            vWorldPosition: aPosition,
            vNormal: aNormal,
        }
    }
    fragmentShader(varying: InnerVarying & Varying, uniform: Uniform): IFragmentResult {
        const {vUv, vWorldPosition, vNormal} = varying;
        const {uDiffuseTexture, uPointLights,  uSpecularTexture, uCameraPoint, uShininess, uAmbient} = uniform;
        const diffuse = uDiffuseTexture.sample(vUv.x, vUv.y);
        const specular = uSpecularTexture.sample(vUv.x, vUv.y);
        let resultColor: Vector3;
        if (uAmbient) {
            resultColor = uAmbient.color.multipliedVector(diffuse);
        } else {
            resultColor = diffuse.clone().toVector3();
        }
        if (uPointLights) {
            for (const pointLight of uPointLights) {
                // 漫反射
                const I = new Vector3();
                const L = vWorldPosition.subed(pointLight.position); // 光的方向, 可能有问题
                const d = L.length();
                const N = vNormal;
                L.normalize();
                I.add(
                    pointLight.color.multipliedVector(diffuse).multipliedScale( Math.max(0, N.dot(L)) )
                )

                // 镜面反色
                const V = uCameraPoint.subed(vWorldPosition).normalize(); // 相机与点的向量
                const H = L.added(V).normalize(); // 中矢量
                const NDotH = Math.max(0, N.dot(H));
                const RS = Math.pow(NDotH, uShininess);
                I.add(pointLight.color.multipliedVector(specular).multipliedScale(RS));

                // 光强度衰减
                const {c0, c1, c2} = pointLight;
                const f = Math.min(1, 1 / (c0 + c1*d + c2*d*d));
                resultColor.add(I.multipliedScale(f));
            }
        }

        // console.log('vUv', vUv.toString());
        // console.log('color',  uTexture.sample(vUv.x,vUv.y).toString());

        return {
            color: resultColor.toVector4(),
            discard: false
        };
    }
}